package kburndown.client.service
{
	import flash.events.Event;
	import flash.geom.Point;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;
	
	import kburndown.client.app.utils.DateHelper;
	import kburndown.client.service.data.ProjectInfo;
	import kburndown.client.service.data.TaskInfo;
	import kburndown.client.service.data.UnitInfo;
	
	import mx.controls.Alert;
	import mx.controls.ToolTip;
	import mx.core.FlexGlobals;
	import mx.core.UIComponent;
	import mx.managers.ToolTipManager;
	import mx.messaging.ChannelSet;
	import mx.messaging.channels.AMFChannel;
	import mx.rpc.AbstractOperation;
	import mx.rpc.AsyncToken;
	import mx.rpc.events.AbstractEvent;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.remoting.RemoteObject;

	public class KBurndownService implements IService
	{
		public static var Method_Ping: String = "ping";
		public static var Method_GetProjectData: String = "getProjectData";
		public static var Method_GetUnits: String = "getUnits";
		public static var Method_GetBurndownGraphData: String = "getBurndownGraphData";
		public static var Method_GetTasksByUnit: String = "getTasksByUnit";
		public static var Method_AddTask: String = "addTask";
		public static var Method_EditTask: String = "editTask";
		public static var Method_DeleteTask: String = "deleteTask";
		public static var Method_FinishTask: String = "finishTask";
		public static var Method_GetTasks: String = "getTasks";
		public static var Method_MoveTask: String = "moveTask";
		public static var Method_MoveUnit: String = "moveUnit";
		public static var Method_ReOpen: String = "reOpen";
		public static var Method_UpDateGraphdata: String = "updateGraphData";

		public static var asynchronismMap: Object = {};
		
		public function KBurndownService()
		{
			_handlers[Method_Ping] = _onPing;
			_handlers[Method_GetProjectData] = _onGetProjectData;
			_handlers[Method_GetUnits] = _onGetUnit;
			_handlers[Method_GetBurndownGraphData] = _onGetBurndownGraphData;
			_handlers[Method_GetTasksByUnit] = _onGetTasksByUnit;
			_handlers[Method_AddTask] = _onAddTask;
			_handlers[Method_EditTask] = _onEditTask;
			_handlers[Method_DeleteTask] = _onDeleteTask;
			_handlers[Method_FinishTask] = _onFinishTask;
			_handlers[Method_GetTasks] = _onGetTasks;
			_handlers[Method_MoveTask] = _onMoveTask;
			_handlers[Method_MoveUnit] = _onMoveUnit;
			_handlers[Method_ReOpen] = _onReOpen;
			_handlers[Method_UpDateGraphdata] = _onUpdataGraphData;
			
			asynchronismMap[Method_MoveTask] = true;
		}

		private static var _service: KBurndownService = new KBurndownService();
		private static var _offlineService: OfflineService = new OfflineService();

		public static var _isOnline: Boolean;
		public static var _url: String;

		public static function connect(url: String = null): void
		{
			if(url == null)
			{
				_isOnline = false;
			}
			else
			{
				_isOnline = true;
				_url = url;
			}
		}

		public static function get instance(): IService
		{
			if (_isOnline)
				return _service;
			else
				return _offlineService;
		}

		private var _remoteObj: RemoteObject;

		private function get remoteObj(): RemoteObject
		{
			if (!_remoteObj)
			{
				var channel: AMFChannel = new AMFChannel("pyamf", _url);
				var channels: ChannelSet = new ChannelSet();
				channels.addChannel(channel);
				_remoteObj = new RemoteObject("KBurndownService");
				_remoteObj.channelSet = channels;
			}
			return _remoteObj;
		}

		private var _requests: Vector.<Object> = new Vector.<Object>();
		private var _handlers: Object = {};
		private var _tokens: Vector.<AsyncToken> = new Vector.<AsyncToken>();
		private var _callbacks: Vector.<Function> = new Vector.<Function>();

		private function _callMethod(method: String, params: Object, callback: Function): void
		{
			_requests.push({method: method, params: params, callback: callback});
			if (_requests.length == 1)
				_send();
		}

		private function _send(): void
		{
			if (_requests.length > 0)
			{
				var app: UIComponent = FlexGlobals.topLevelApplication as UIComponent;
				app.mouseEnabled = false;
				app.mouseChildren = false;
				var request: Object = _requests[0];
				var method: String = request.method;
				var params: Object = request.params;
				var callback: Function = request.callback;

				if(asynchronismMap[method] == null)
				ServiceToolTip.showTooltip(method);

				var op: AbstractOperation = remoteObj.getOperation(method);
				if (params)
					op.arguments = params;
				op.addEventListener(ResultEvent.RESULT, _onService);
				op.addEventListener(FaultEvent.FAULT, _onService);
				var token: AsyncToken;
				token = op.send();
				_tokens.push(token);
				_callbacks.push(callback);
			}

		}

		private function _onService(event: AbstractEvent): void
		{
			var target: AbstractOperation = event.target as AbstractOperation;
			var arguments: Object = target.arguments;
			var tokenIndex: int = _tokens.indexOf(event.token);
			if (tokenIndex != -1)
			{

				if (event.type == ResultEvent.RESULT)
				{
					_handlers[target.name](event.type, ResultEvent(event).result, _callbacks[tokenIndex], arguments);
				}
				else
				{
					_handlers[target.name](event.type, "wrong", _callbacks[tokenIndex], arguments);
				}

				_requests.splice(0, 1);
				_tokens.splice(tokenIndex, 1);
				_callbacks.splice(tokenIndex, 1);
				var app: UIComponent = FlexGlobals.topLevelApplication as UIComponent;
				app.mouseEnabled = true;
				app.mouseChildren = true;
				ServiceToolTip.hideToolTip();
				_send();
			}
		}

		//---------------------------------------------------------------------------------
		//
		//		接口
		//
		//----------------------------------------------------------------------------------

		public function ping(callBack: Function = null): void
		{
			_callMethod("ping", "ping", callBack);
		}

		private function _onPing(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			if (callback != null)
				callback(resultType);
		}

		public function getInitData(callback: Function = null): void
		{
			getProjectData(_GetProjectData);
			
			function _GetProjectData(result: String):void
			{
				if(result == ResultEvent.RESULT)
				{
					getUnits();
					getTasks();
					getBurndownGraphData(callback);
				}
				else
				{
					(FlexGlobals.topLevelApplication as KBurnDown).init();
					Alert.show("请确保已经连接到服务器");
				}
			}
			
		}

		public function getProjectData(callBack: Function = null): void
		{
			_callMethod(Method_GetProjectData, null, callBack);
		}

		private function _onGetProjectData(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			if (resultType == ResultEvent.RESULT)
				ProjectInfo.instance.setProjectData(result);
			if (callback != null)
				callback(resultType);
		}

		public function getUnits(callback: Function = null): void
		{
			_callMethod(Method_GetUnits, null, callback);
		}

		private function _onGetUnit(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			ProjectInfo.instance.setUnitData(result);
			if (callback != null)
				callback();
		}

		public function getBurndownGraphData(callback: Function = null): void
		{
			_callMethod(Method_GetBurndownGraphData, null, callback);
		}

		private function _onGetBurndownGraphData(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			ProjectInfo.instance.setBurndownGraphData(result);
			if (callback != null)
				callback();
		}

		public function getTasks(callback: Function = null): void
		{
			_callMethod(Method_GetTasks, null, callback);
		}

		private function _onGetTasks(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			ProjectInfo.instance.setTasksData(result);
			if (callback != null)
				callback();
		}

		public function getTasksByUnit(id: int, callback: Function = null): void
		{
			var param: Array = [];
			param.push(id);
			_callMethod(Method_GetTasksByUnit, param, callback);
		}

		private function _onGetTasksByUnit(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
//		 arguments
			var id: int = arguments[0];
			ProjectInfo.instance.setTasksDataByUnit(id, result);
			if (callback != null)
				callback();

		}

		public function addTask(name: String, content: String, icon: String, ownerId: int, duration: Number, callback: Function = null): void
		{
			var param: Array = [];
			param.push(name, content, icon, ownerId, duration);
			_callMethod(Method_AddTask, param, callback);
		}

		private function _onAddTask(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			if (resultType == ResultEvent.RESULT)
			{
				var task: TaskInfo = new TaskInfo();
				task.name = arguments[0];
				task.content = arguments[1];
				task.icon = arguments[2];
				task.owner = UnitInfo.getUnitById(arguments[3]);
				task.duration = arguments[4];
				task.id = result as int;
				ProjectInfo.instance.addTaskByData(task);
				ProjectInfo.instance.changeTodayResult(task.duration);
			}

			if (callback != null)
				callback(resultType, task);
		}

		public function stretchTaskDuration(task: TaskInfo, newDuration: int, callback: Function = null): void
		{
			editTask(task.id, task.name, task.content, task.icon, newDuration, callback);
		}

		public function editTask(taskId: int, name: String, content: String, icon: String, duration: Number, callback: Function = null): void
		{
			var params: Array = [taskId as int, name, content, icon, duration];
			_callMethod(Method_EditTask, params, callback);
		}

		private function _onEditTask(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			if (resultType == ResultEvent.RESULT)
			{
				var taskId: int = arguments[0];
				var taskInfo: TaskInfo = ProjectInfo.instance.getTaskById(taskId);
				var _oldDuration: Number = taskInfo.duration;
				ProjectInfo.instance.setTaskInfoData(taskInfo, result);
				var _newDuration: Number = taskInfo.duration;
				if (_oldDuration != _newDuration)
				{
					var changeValue: Number = _newDuration - _oldDuration;
					ProjectInfo.instance.changeTodayResult(changeValue);
				}
			}
			if (callback != null)
				callback(resultType);
		}

		public function moveTask(taskId: int, anchorTaskId: int, callback: Function = null): void
		{
			if (taskId == anchorTaskId)
				return;

			var params: Array;
			if (anchorTaskId != -1)
				params = [taskId, anchorTaskId];
			else
				params = [taskId, null];
			_callMethod(Method_MoveTask, params, callback);
		}

		private function _onMoveTask(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			if (resultType == ResultEvent.RESULT)
			{
				var taskId: int = arguments[0];
				var anchorTaskId: int = arguments[1];
				var taskInfo: TaskInfo = ProjectInfo.instance.getTaskById(taskId);
				var unitInfo: UnitInfo = taskInfo.owner;
				unitInfo.setMoveTask(taskId, anchorTaskId);
			}
			if (callback != null)
				callback(resultType);
		}


		public function finishTask(taskId: int, comment: String, callback: Function = null): void
		{
			var date: Date = DateHelper.getToday();
			var params: Array = [taskId, date];
			_callMethod(Method_FinishTask, params, callback);
		}

		private function _onFinishTask(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			var taskid: int = arguments[0] as int;
			var task: TaskInfo = ProjectInfo.instance.getTaskById(taskid);
			task.finishedDate = DateHelper.getToday();
			var unit: UnitInfo = task.owner;
			unit.setTaskFinished(task);

			ProjectInfo.instance.changeTodayResult(-task.duration);
			callback(resultType, task);
//			var task: TaskInfo = UnitInfo.
		}

		public function deleteTask(taskId: int, callback: Function = null): void
		{
			var param: Array = [taskId];
			_callMethod(Method_DeleteTask, param, callback);
		}

		private function _onDeleteTask(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			var taskid: int = arguments[0] as int;
			var task: TaskInfo = ProjectInfo.instance.getTaskById(taskid);
//			task.finishedDate = DateHelper.getToday();
			task.deleted = true;
			var unit: UnitInfo = task.owner;
			unit.setTaskDeleted(task);
			ProjectInfo.instance.changeTodayResult(-task.duration);
			callback(resultType, task);
		}

		public function moveUnit(unitId: int, posX: Number, posY: Number, callback: Function = null): void
		{
			var param: Array = [unitId, posX, posY];
			_callMethod(Method_MoveUnit, param, callback);
		}

		private function _onMoveUnit(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			if (resultType == ResultEvent.RESULT)
			{
				var unitId: int = arguments[0];
				var newX: Number = arguments[1];
				var newY: Number = arguments[2];
				var unit: UnitInfo = UnitInfo.getUnitById(unitId);
				unit.posX = newX;
				unit.posY = newY;
			}
			if (callback != null)
				callback(resultType);
		}
		
		public function restore(taskId: int, anchorTaskId: int, callback: Function): void
		{
			var params: Array = [taskId, anchorTaskId];
			_callMethod(Method_ReOpen,params, callback);
		}
		
		private function _onReOpen(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			var taskId: int = arguments[0] as int;
			var anchorTaskId: int = arguments[1] as int;
			var task: TaskInfo ;
			if(resultType == ResultEvent.RESULT)
			{
				task = ProjectInfo.instance.getTaskById(taskId);
				ProjectInfo.instance.setTaskReOpen(task, anchorTaskId);
			}
			if(callback != null)
				callback(resultType, task);
		}
		
		public function updataGraphData(date: Date, callback: Function):void
		{
			ProjectInfo.instance.updataGraphData();
			if(callback != null)
				callback();
//			var params: Array = [date];
//			_callMethod(Method_UpDateGraphdata, params, callback);
		}
		
		private function _onUpdataGraphData(resultType: String, result: Object, callback: Function, arguments: Object): void
		{
			
		}
	}
}